home *** CD-ROM | disk | FTP | other *** search
/ InterCD 2001 May / may_2001.iso / intercd / root / Multimedia / ^DivX_Article / virtualdub / VirtualDub-source-1_4d / SceneDetector.cpp < prev    next >
Encoding:
C/C++ Source or Header  |  2001-03-20  |  5.0 KB  |  202 lines

  1. //    VirtualDub - Video processing and capture application
  2. //    Copyright (C) 1998-2001 Avery Lee
  3. //
  4. //    This program is free software; you can redistribute it and/or modify
  5. //    it under the terms of the GNU General Public License as published by
  6. //    the Free Software Foundation; either version 2 of the License, or
  7. //    (at your option) any later version.
  8. //
  9. //    This program is distributed in the hope that it will be useful,
  10. //    but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. //    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  12. //    GNU General Public License for more details.
  13. //
  14. //    You should have received a copy of the GNU General Public License
  15. //    along with this program; if not, write to the Free Software
  16. //    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  17.  
  18. #include <crtdbg.h>
  19. #include <math.h>
  20.  
  21. #include "VBitmap.h"
  22. #include "Error.h"
  23.  
  24. #include "SceneDetector.h"
  25.  
  26. SceneDetector::SceneDetector(PixDim width, PixDim height) {
  27.     cur_lummap = last_lummap = NULL;
  28.     last_valid = FALSE;
  29.     first_diff = TRUE;
  30.  
  31.     cut_threshold = 50 * tile_w * tile_h;
  32.     fade_threshold = 4 * tile_w * tile_h;
  33.  
  34.     try {
  35.         tile_w = (width + 7)/8;
  36.         tile_h = (height + 7)/8;
  37.  
  38.         if (    !(cur_lummap  = new Pixel[tile_h * tile_w])
  39.             ||    !(last_lummap = new Pixel[tile_h * tile_w]))
  40.  
  41.             throw MyMemoryError();
  42.     } catch(...) {
  43.         _destruct();
  44.         throw;
  45.     }
  46. }
  47.  
  48. SceneDetector::_destruct() {
  49.     delete[] cur_lummap;
  50.     delete[] last_lummap;
  51. }
  52.  
  53. SceneDetector::~SceneDetector() {
  54.     _destruct();
  55. }
  56.  
  57. //////////////////////////////////////////////////////////////////////////
  58.  
  59. void SceneDetector::SetThresholds(int cut_threshold, int fade_threshold) {
  60.     this->cut_threshold        = (cut_threshold * tile_w * tile_h)/16;
  61.     this->fade_threshold    = (fade_threshold * tile_w * tile_h * 3)/16.0;
  62. }
  63.  
  64. BOOL SceneDetector::Submit(VBitmap *vbm) {
  65.     long last_frame_diffs = 0;
  66.     long lum_total = 0;
  67.     double lum_sq_total = 0.0;
  68.     long len = tile_w * tile_h;
  69.  
  70.     if (vbm->w > tile_w*8 || vbm->h > tile_h*8 || !cut_threshold || !fade_threshold)
  71.         return FALSE;
  72.  
  73.     FlipBuffers();
  74.     BitmapToLummap(cur_lummap, vbm);
  75.  
  76.     if (!last_valid) {
  77.         last_valid = TRUE;
  78.         return FALSE;
  79.     }
  80.  
  81. /////////////
  82.  
  83.     Pixel *t1 = cur_lummap, *t2 = last_lummap;
  84.     BOOL is_fade;
  85.  
  86.     do {
  87.         Pixel c1 = *t1++;
  88.         Pixel c2 = *t2++;
  89.  
  90.         last_frame_diffs +=      abs((int)(c2>>16)-(int)(c1>>16))
  91.                             + abs((int)((c2>>8)&255) -(int)((c1>>8)&255))
  92.                             + abs((int)(c2&255)-(int)(c1&255));
  93.  
  94.         long lum = ((c1>>16)*54 + ((c1>>8)&255)*183 + (c1&255)*19 + 128)>>8;
  95.  
  96.         lum_total += lum;
  97.         lum_sq_total += (double)lum * (double)lum;
  98.     } while(--len);
  99.  
  100.     lum_sq_total *= tile_w*tile_h;
  101.  
  102. //    _RPT3(0,"Last frame diffs=%ld, lum(linear)=%ld, lum(rms)=%f\n",last_frame_diffs,lum_total,sqrt(lum_sq_total));
  103.  
  104.     if (fade_threshold) {
  105.         is_fade = fabs(sqrt(lum_sq_total) - (double)lum_total) < fade_threshold;
  106.  
  107.         if (first_diff) {
  108.             last_fade_state = is_fade;
  109.         } else {
  110.             // If we've encountered a new fade, return 'scene changed'
  111.  
  112.             if (!last_fade_state && is_fade) return TRUE;
  113.  
  114.             // Hit the end of an initial fade?
  115.  
  116.             if (last_fade_state && !is_fade)
  117.                 last_fade_state = FALSE;
  118.         }
  119.     }
  120.  
  121.     // Cut/dissolve detection
  122.  
  123.     return cut_threshold ? last_frame_diffs > cut_threshold : FALSE;
  124. }
  125.  
  126. void SceneDetector::Reset() {
  127.     last_valid = FALSE;
  128. }
  129.  
  130. //////////////////////////////////////////////////////////////////////////
  131.  
  132. extern "C" Pixel __cdecl asm_scene_lumtile32(void *src, long w, long h, long pitch);
  133. extern "C" Pixel __cdecl asm_scene_lumtile24(void *src, long w, long h, long pitch);
  134. extern "C" Pixel __cdecl asm_scene_lumtile16(void *src, long w, long h, long pitch);
  135.  
  136. void SceneDetector::BitmapToLummap(Pixel *lummap, VBitmap *vbm) {
  137.     char *src, *src_row = (char *)vbm->data;
  138.     int mh = 8;
  139.     long w,h;
  140.  
  141.     h = (vbm->h+7)/8;
  142.  
  143.     switch(vbm->depth) {
  144.     case 32:
  145.         do {
  146.             if (h<=1 && (vbm->h&7)) mh = vbm->h&7;
  147.  
  148.             src = src_row; src_row += vbm->pitch*8;
  149.             w = vbm->w/8;
  150.             do {
  151.                 *lummap++ = asm_scene_lumtile32(src, 8, mh, vbm->pitch);
  152.                 src += 32;
  153.             } while(--w);
  154.  
  155.             if (vbm->w & 7) {
  156.                 *lummap++ = asm_scene_lumtile32(src, vbm->w&7, mh, vbm->pitch);
  157.             }
  158.         } while(--h);
  159.         break;
  160.     case 24:
  161.         do {
  162.             if (h<=1 && (vbm->h&7)) mh = vbm->h&7;
  163.  
  164.             src = src_row; src_row += vbm->pitch*8;
  165.             w = vbm->w/8;
  166.             do {
  167.                 *lummap++ = asm_scene_lumtile24(src, 8, mh, vbm->pitch);
  168.                 src += 24;
  169.             } while(--w);
  170.  
  171.             if (vbm->w & 7) {
  172.                 *lummap++ = asm_scene_lumtile24(src, vbm->w&7, mh, vbm->pitch);
  173.             }
  174.         } while(--h);
  175.         break;
  176.     case 16:
  177.         do {
  178.             if (h<=1 && (vbm->h&7)) mh = vbm->h&7;
  179.  
  180.             src = src_row; src_row += vbm->pitch*8;
  181.             w = vbm->w/8;
  182.             do {
  183.                 *lummap++ = asm_scene_lumtile16(src, 4, mh, vbm->pitch);
  184.                 src += 16;
  185.             } while(--w);
  186.  
  187.             if (vbm->w & 6) {
  188.                 *lummap++ = asm_scene_lumtile16(src, (vbm->w&6)/2, mh, vbm->pitch);
  189.             }
  190.         } while(--h);
  191.         break;
  192.     }
  193. }
  194.  
  195. void SceneDetector::FlipBuffers() {
  196.     Pixel *t;
  197.  
  198.     t = cur_lummap;
  199.     cur_lummap = last_lummap;
  200.     last_lummap = t;
  201. }
  202.